parser grammar Javasint;

/*
//Solucion del if con backtrack=false:
if_statement: IF^ ifexp ifbloque (elseif)?;
ifexp: LPARENTHESIS! expression RPARENTHESIS!; 
ifbloque: (bloque_stats | statement); 
elseif: ELSE^ (bloque_stats | statement);

*/


options {
  language = Java;
  tokenVocab = Javalex;
  backtrack = true; //para resolver ambiguedades
  //k = 3;
}

@header {
   package samplejava.antlr;
      
   import samplejava.compiler.*;
}

@members {
	static final int NULO = -99; //para la funcion gen: que no genere el parametro
	//static final CADENA_NULL = "";
	
	SymTable tabla = new SymTable();
	public StringBuilder codigoSAM = new StringBuilder(); // Contiene el codigo SAM que se va generando dinamicamente
	
	boolean debug = true;
	//boolean tipoFunc = false; //para saber si funcion devuelve tipo o no
	boolean ref = false;
	boolean esFloat = false;
	
	void printTS(String mensaje) {
		if (debug)
		  System.out.println(mensaje + "\n" + tabla);
	}
	
	//funciones para generar codigo
	void genComment(String comment) {
		codigoSAM.append("\t\t;" + comment); //el \n ya lo hace gen
	}
	
	void genNewLine() {
		codigoSAM.append("\n");
	}
	
	void genEtiqueta(String name) {
	   codigoSAM.append("\n\n" + name + ":");
	}
	
  void gen(String nameInstr) { //para funciones HALT, CALLI etc.
      codigoSAM.append("\n\t" + nameInstr);
  }
    
	void gen(String nameInstr, int n, int d, String reg) {
		codigoSAM.append("\n\t" + nameInstr);
		if (n != NULO)
		  codigoSAM.append("\t(" + n + ")");
	    else
          codigoSAM.append("\t\t");	  
          
		if (d != NULO)
          codigoSAM.append("\t" + d);
        else
          codigoSAM.append("\t\t");
          
        if (!reg.equals(""))
          codigoSAM.append("[" + reg + "]");
        else
          codigoSAM.append("\t");
	}
	
    void genCall(int n, String name) {
       codigoSAM.append("\n\tCALL \t(" + n + ") \t" + name);
    }
    
    void genCall(String reg, String name) {
       codigoSAM.append("\n\tCALL \t(" + reg + ") \t" + name);
    }
    
    void genOperation(int tipo, String op, int tipo1, int tipo2) { //genera codigo para: E -> E1 op E2
    	if ((tipo1 == Tipos.INT) && (tipo2 == Tipos.INT)) 
    	   genCall(Tipos.getSize(tipo), op);
    	else if ((tipo1 == Tipos.INT) && (tipo2 == Tipos.LONG)) {
    	   genCall(Tipos.getSize(tipo1), "to21");
    	   genCall(Tipos.getSize(tipo), op);
    	}
    	else if ((tipo1 == Tipos.LONG) && (tipo2 == Tipos.INT)) {
    	   genCall(Tipos.getSize(tipo), "to22");
           genCall(Tipos.getSize(tipo), op);
    	}
        else if ((tipo1 == Tipos.LONG) && (tipo2 == Tipos.LONG))
           genCall(Tipos.getSize(tipo), op);
    }
    
    void genAssignL(String id, char op, ETipo etipo) {
    	   EntryTS entrada = tabla.find(id);
    	   
    	   if ((entrada != null) && (etipo != null)) { //estupido: etipo va a ser null (ver en gramatica)
	    	   long value = entrada.getValue();
	    	   long decimal = entrada.getDecimalValue();
	    	   
	    	   switch (op) { //XXX: cuidado no se tiene bien en cuenta para float en div, mult, mod 
	    	   	 case '+': value += etipo.getValue(); decimal += etipo.getDecimalValue(); break;
	    	   	 case '-': value -= etipo.getValue(); decimal -= etipo.getDecimalValue(); break;
	    	   	 case '*': value *= etipo.getValue(); decimal *= etipo.getDecimalValue(); break;
	    	   	 case '/': value /= etipo.getValue(); decimal /= etipo.getDecimalValue(); break;
	    	   	 //mod, pero no admite simbolo //case '+': value += etipo.getValue(); decimal += etipo.getDecimalValue(); break;
	    	   	 default: break;
	    	   }
	    	   
	           entrada = tabla.modifyValue(id, value, decimal);    
    	   }
    	   
           if (entrada != null) { //estupido: solo se ejecutara esto xD
              if (entrada.isGlobal())
                gen("LOAD", entrada.getSize(), entrada.getOffset(), "SB"); 
              else
                gen("LOAD", entrada.getSize(), entrada.getOffset(), "LB");
           }
    }
    
    void genAssignR(String id, String op) {
           EntryTS entrada = tabla.find(id);
           if (entrada != null) {
              genCall(entrada.getSize(), op);
              genCall(entrada.getSize(), "id");
              if (entrada.isGlobal())
                  gen("STORE", entrada.getSize(), entrada.getOffset(), "SB");
              else
                  gen("STORE", entrada.getSize(), entrada.getOffset(), "LB");
           }
    }
    
    //fin funciones de generar codigo
    
	
	/* int crearTipo(int tipo1, int tipo2) { //dada Expresion: E1 op E2, devuelve tipo devuelto
	   if ((tipo1 == Tipos.INT) && (tipo2 == Tipos.INT)) return Tipos.INT;
	   else if ((tipo1 == Tipos.INT) && (tipo2 == Tipos.LONG)) return Tipos.LONG;
	   else if ((tipo1 == Tipos.LONG) && (tipo2 == Tipos.INT)) return Tipos.LONG;
       else if ((tipo1 == Tipos.LONG) && (tipo2 == Tipos.LONG)) return Tipos.LONG;
       else return Tipos.TYPE_ERROR;
	}*/
	 
	 ETipo crearTipo(ETipo tipo1, ETipo tipo2) { //dada Expresion: E1 op E2, devuelve tipo devuelto
	   if ((tipo1 == null) || (tipo2 == null))
	     return new ETipo_Error();
	     
      if ((tipo1.getIdTipo() == Tipos.INT) && (tipo2.getIdTipo() == Tipos.INT)) return new ETipo_Int();
      else if ((tipo1.getIdTipo() == Tipos.INT) && (tipo2.getIdTipo() == Tipos.LONG)) return new ETipo_Long();
      else if ((tipo1.getIdTipo() == Tipos.LONG) && (tipo2.getIdTipo() == Tipos.INT)) return new ETipo_Long();
      else if ((tipo1.getIdTipo() == Tipos.LONG) && (tipo2.getIdTipo() == Tipos.LONG)) return new ETipo_Long();
      
      else if ((tipo1.getIdTipo() == Tipos.INT) && (tipo2.getIdTipo() == Tipos.FLOAT)) return new ETipo_Float();
      else if ((tipo1.getIdTipo() == Tipos.FLOAT) && (tipo2.getIdTipo() == Tipos.INT)) return new ETipo_Float();
      
      else if ((tipo1.getIdTipo() == Tipos.LONG) && (tipo2.getIdTipo() == Tipos.FLOAT)) return new ETipo_Float();
      else if ((tipo1.getIdTipo() == Tipos.FLOAT) && (tipo2.getIdTipo() == Tipos.LONG)) return new ETipo_Float();
      
      else if ((tipo1.getIdTipo() == Tipos.FLOAT) && (tipo2.getIdTipo() == Tipos.FLOAT)) return new ETipo_Float();
      else return new ETipo_Error();
   }
	
	
  /* protected void mismatch(IntStream input, int ttype, BitSet follow)
    throws RecognitionException
  {
    throw new MismatchedTokenException(ttype, input);
  }*/
}

/*
@rulecatch { 
  catch (RecognitionException e) {
    throw e;
  } 
} */



//**************************************************************************************/
//GRAMATICA:

//program: data_def* function_def* EOF ;

program:     
            data_def* 
            
            { //gen("PUSH", NULO, 3, "");
            genCall("SB", "main");
            gen("HALT"); genComment("fin del programa"); genNewLine();
            }
            
            function_def* EOF ; // printTS("\nFINAL: \n");
            
            
//def: (type ID LPARENTHESIS) => function_def | data_def;

//def: (type (ASTERISK)? ID (COMMA | SEMICOLON) ) => data_def | function_def;

data_def: t=type declarator[$t.etipo] (COMMA declarator[$t.etipo])* SEMICOLON; //atributo heredado etipo
         
declarator [ETipo etipo] returns [String name]:  //atributo heredado: etipo, sintetizado: name
    id=ID 
    { $name = $id.getText();
      tabla.lookUp($name, EntryTS.VAR, etipo); 
      gen("PUSH", NULO, etipo.getSize(), "");
      genComment($name);
    };
    

type returns [ETipo etipo] : s=simple_type { $etipo = $s.etipo; }
         | p=pointer_type { $etipo = $p.etipo; };

simple_type returns [ETipo etipo]: INT { $etipo = new ETipo_Int(); } 
      | LONG { $etipo = new ETipo_Long(); } 
      | FLOAT { $etipo = new ETipo_Float(); } 
      | VOID { $etipo = new ETipo_Void(); } ;
   
   
pointer_type returns [ETipo etipo]: s=simple_type ASTERISK { $etipo = new ETipo_Pointer($s.etipo); } ;
    
    
    
function_def: 
        //{ printTS("\nANTES DE FUNCION:\n"); } 
        t=type    //(type {tipoFunc = true;} )? //ya cambiamos gramatica, podria ser void
        h=function_header[$t.etipo]  //funcion_header introduce funcion, blkPush(), parametros     
        function_body 
        
        { //printTS("\nAL FINAL DE LA FUNCION: \n");
          tabla.blkPop(); 
          //printTS("\nDESPUES DE POP: \n");
          if ($t.etipo.getIdTipo() != Tipos.VOID) // tipoFunc == true
             gen("RETURN", 1, 1, ""); //funcion retorna algo
          else 
             gen("RETURN", 0, 1, ""); //no retorna ningun valor
             
          genComment("fin de funcion " + $h.name + "\n"); //genNewLine();
        } ;
        
function_header [ETipo etipo] returns [String name] : //atributo heredado etipo 
            d=declarator[etipo]
           { genEtiqueta($d.name);
           
            if ($d.name.equals("main"))
               tabla.modify("main", EntryTS.FUNC, 0, Tipos.INT);
            else 
               tabla.lookUp($d.name, EntryTS.FUNC, 0, etipo.getIdTipo()); 
            
             tabla.blkPush(); //push despues de nombre de funcion y antes de parametros
             $name = $d.name;
            }
            
            parameter_list;
            
            
parameter_list: LPARENTHESIS parameters_decl? RPARENTHESIS;

parameters_decl: parameter (COMMA parameter)*;

parameter: type (AND_BIN { ref = true;} )? id=ID 
       {
           if (ref) {
               EntryTS entrada = tabla.lookUp($id.getText(), EntryTS.PARAM_REF, $type.etipo);
               gen("LOADA", NULO, entrada.getOffset(), "LB"); //paso por referencia
               genComment("parametro " + $id.getText() + " por referencia"); 
           }
           else {
               EntryTS entrada = tabla.lookUp($id.getText(), EntryTS.PARAM, $type.etipo); //tipo int por defecto 
               gen("LOAD", entrada.getSize(), entrada.getOffset(), "LB"); //paso por valor
               genComment("parametro " + $id.getText() + " por valor"); 
           }
           
           ref = false; //para siguientes parametros
       };


         
               
function_body: LCURLY (data_def | statement)* RCURLY;
statement: (expression)? SEMICOLON  
            {  genComment("fin statm\n"); } //gen("POP", $expression.etipo.getSize(), NULO, ""); //se omite, aunq deberia estar
        | LCURLY { tabla.blkPush();} data_def* statement* { tabla.blkPop();} RCURLY
        | IF LPARENTHESIS expression RPARENTHESIS statement (ELSE statement)?
        | WHILE LPARENTHESIS expression RPARENTHESIS statement
        | BREAK SEMICOLON
        | CONTINUE SEMICOLON
        | PRINT LPARENTHESIS c=CADENA RPARENTHESIS SEMICOLON { System.out.println($c.getText()); }
        | PRINT_TS LPARENTHESIS c=CADENA RPARENTHESIS SEMICOLON { printTS($c.getText()); } 
        | RETURN (expression)? SEMICOLON 
         { if (tabla.getBlockLevel() == 0)
         	gen("HALT");
           else
            gen("RETURN", 0, 0, ""); //aun por saber
         };

expression returns [ETipo etipo, boolean ref, int offset, int blockLevel]: 
            binary { $etipo = $binary.etipo; }
            (COMMA 
            { gen("POP", $binary.etipo.getSize(), NULO, ""); genComment("comma expr\n"); } 
            expression)*;
            
            
binary returns [ETipo etipo, boolean ref, int offset, int blockLevel]:
       (ID ASSIGN NEW) => n=assign_new 
       { $etipo = $n.etipo; 
       	 $ref = $n.ref;
       	 $offset = $n.offset;
       	 $blockLevel = $n.blockLevel;
       }
       
       | ASTERISK id=ID ASSIGN b=binary
       {
       	 EntryTS entrada = tabla.find($id.getText());
       	  if (entrada == null)
                System.out.println("Error semantico, no encontrada variable " + $id.getText());
            else {        
                if (entrada.getTipo() != Tipos.POINTER)
                   System.out.println("Error: variable " + $id.getText() + " no es de tipo puntero");
                   
                entrada.getApuntado().setValue($b.etipo.getValue()); //garantizado: modificado en tabla
                entrada.getApuntado().setDecimalValue($b.etipo.getDecimalValue());
                gen("STORE", entrada.getApuntado().getSize(), entrada.getETipo().getIndice(), "HB");
	       	 
	       	 }
       	
       }
       
       | id=ID ASSIGN b=binary 
       {  EntryTS entrada = tabla.find($id.getText());
       	  entrada.setValue($b.etipo.getValue()); //se asignan los valores y el puntero (da igual tipo)
       	  entrada.setDecimalValue($b.etipo.getDecimalValue()); //se garantiza cambio en tabla
       	  entrada.setPuntero($b.etipo.getPuntero());
        //if (entrada.getTipo() != Tipos.POINTER) {
        //EntryTS entrada = tabla.modifyValue($id.getText(), $b.etipo.getValue(), $b.etipo.getDecimalValue());
        genCall(entrada.getSize(), "id");
        genComment("\t" + $id.getText() + " = expr");
        if (entrada != null) //si es null: error semantico
           if (entrada.getKind() == EntryTS.PARAM_REF) //se podria tambien con tabla.findKind()
              gen("STOREI", entrada.getSize(), NULO, "");
           else 
              if (entrada.isGlobal())
                gen("STORE", entrada.getSize(), entrada.getOffset(), "SB"); 
              else
                gen("STORE", entrada.getSize(), entrada.getOffset(), "LB"); 
       }
       
        
        //XXX: b.etipo aun es null xq aun no se ha resuelto b. solucion: 
        //poner accion despues, pero eso cambiaria el orden de la generacion de codigo
       | id=ID { genAssignL($id.getText(), '+', $b.etipo); }
         APLUS b=binary { genAssignR($id.getText(), "add"); genComment("+="); }
       
       | id=ID { genAssignL($id.getText(), '*', $b.etipo); }
         AMULT b=binary { genAssignR($id.getText(), "mult"); genComment("*="); }
       
       | id=ID { genAssignL($id.getText(), '/', $b.etipo); }
         ADIV b=binary { genAssignR($id.getText(), "div"); genComment("/="); }
       
       | id=ID { genAssignL($id.getText(), '-', $b.etipo); }
         AMINUS b=binary { genAssignR($id.getText(), "sub"); genComment("-="); }
       
       | id=ID { genAssignL($id.getText(), '+', $b.etipo); }
         AMOD b=binary { genAssignR($id.getText(), "mod"); genComment("mod="); }
            
            
       //***** E1 op E2  ***** %
       | u=unary PLUS b=binary
        { $etipo = crearTipo($u.etipo, $b.etipo); 
          $etipo.setValue($u.etipo.getValue() + $b.etipo.getValue());
          genOperation($etipo.getIdTipo(), "add", $u.etipo.getIdTipo(), $b.etipo.getIdTipo());
          genComment("+");
        }
       
       | u=unary MINUS b=binary
       {  $etipo = crearTipo($u.etipo, $b.etipo); 
          $etipo.setValue($u.etipo.getValue() - $b.etipo.getValue());
          genOperation($etipo.getIdTipo(), "sub", $u.etipo.getIdTipo(), $b.etipo.getIdTipo());
          genComment("-");
          //XXX: falta ref, etc
        }
          
       | u=unary ASTERISK b=binary       
       { $etipo = crearTipo($u.etipo, $b.etipo); 
          $etipo.setValue($u.etipo.getValue() * $b.etipo.getValue());
          genOperation($etipo.getIdTipo(), "mult", $u.etipo.getIdTipo(), $b.etipo.getIdTipo());
          genComment("*");
        }
         
       | u=unary DIV b=binary 
       { $etipo = crearTipo($u.etipo, $b.etipo); 
          $etipo.setValue( (long) ($u.etipo.getValue() / $b.etipo.getValue()) );
          genOperation($etipo.getIdTipo(), "div", $u.etipo.getIdTipo(), $b.etipo.getIdTipo());
          genComment("/");
        }
         
       | u=unary MOD b=binary
       { $etipo = crearTipo($u.etipo, $b.etipo); 
          $etipo.setValue($u.etipo.getValue() + $b.etipo.getValue()); //XXX: 
          genOperation($etipo.getIdTipo(), "mod", $u.etipo.getIdTipo(), $b.etipo.getIdTipo());
          genComment("mod");
        }
         
       | unary AND_BIN binary
       | unary OR_BIN binary
       | unary POW binary
       
       | unary LESS binary
       | unary GREATER binary
       | unary NOTEQUAL binary
       | unary EQUALS binary
       | unary LESSEQUAL binary
       | unary GREATEQUAL binary
       
       | u=unary 
       { $etipo = $u.etipo;
         $ref = $u.ref;
         $offset = $u.offset;
         $blockLevel = $u.blockLevel;
       } ;
       
unary returns [ETipo etipo, boolean ref, int offset, int blockLevel]:
            (INC id=ID | id=ID INC) 
            {  EntryTS entrada = tabla.find($id.getText());
               if (entrada == null)
                  System.out.println("Error semantico, no encontrada variable" + $id.getText());
               else {
               	  if (entrada.getTipo() == Tipos.POINTER)
               	    entrada.getETipo().setIndice(entrada.getETipo().getIndice() + 1);
               	  else
               	    entrada.setValue(entrada.getValue() + 1); //++ solo a parte entera
               	    
                  $etipo = entrada.getETipo();
                  $ref = false;
                  $offset = entrada.getOffset();
                  $blockLevel = entrada.getBlockLevel();
               
                  if (entrada.isGlobal())
                     gen("LOADA", NULO, entrada.getOffset(), "SB");
                  else
                     gen("LOADA", NULO, entrada.getOffset(), "LB");
                  
                  genCall(entrada.getSize(), "inc");
                  genComment("++" + $id.getText());
               } //if entrada null
            }
            
            | (DEC id=ID | id=ID DEC)             
            {  EntryTS entrada = tabla.find($id.getText());
               if (entrada == null)
                  System.out.println("Error semantico, no encontrada variable" + $id.getText());
               else {
               	  if (entrada.getTipo() == Tipos.POINTER)
                    entrada.getETipo().setIndice(entrada.getETipo().getIndice() - 1);
                  else
                    entrada.setValue(entrada.getValue() + 1); //++ solo a parte entera
                    
                  $etipo = entrada.getETipo();
                  $ref = false;
                  $offset = entrada.getOffset();
                  $blockLevel = entrada.getBlockLevel();
               
                  if (entrada.isGlobal())
                     gen("LOADA", NULO, entrada.getOffset(), "SB");
                  else
                     gen("LOADA", NULO, entrada.getOffset(), "LB");
                  
                  genCall(entrada.getSize(), "dec");
                  genComment("--" + $id.getText());
               } //if entrada null
            }
            
            | p=primary   
            { $etipo = $p.etipo;
              $ref = $p.ref;
              $offset = $p.offset;
              $blockLevel = $p.blockLevel; };
            
            
primary returns [ETipo etipo, boolean ref, int offset, int blockLevel]:
        variable { $etipo = $variable.etipo; }
       
        | n=NUMERO (DOT n2=NUMERO { esFloat = true;} )?   // NUMERO = CONST
        { 
          if (!esFloat) {
             $etipo = new ETipo_Int(Long.parseLong($n.getText())); //por defecto un numero es int
              gen("LOADL", NULO, new Long($etipo.getValue()).intValue(), "");
              genComment("constante entera " + $etipo.getValue());
          }
          else {  
             $etipo = new ETipo_Float(Long.parseLong($n.getText()), Long.parseLong($n2.getText()));
             esFloat = false; //para los siguientes
             gen("LOADL", NULO, 0, ""); 
             gen("LOADL", NULO, new Long($etipo.getValue()).intValue(), ""); 
             gen("LOADL", NULO, 0, "");
             gen("LOADL", NULO, new Long($etipo.getDecimalValue()).intValue(), "");
             genComment("constante float " + $etipo.getValue() + "." + $etipo.getDecimalValue());
          }    
          
          $ref = false;
          $offset = 0;
          $blockLevel = tabla.getBlockLevel();
        }
         
          
        | LPARENTHESIS e=expression RPARENTHESIS 
        {
            $etipo = $e.etipo;
            $ref = $e.ref;
            $offset = $e.offset;
            $blockLevel = $e.blockLevel;
        }
        
        | id=ID LPARENTHESIS argument_list? RPARENTHESIS  //function_statement
        {   EntryTS entrada = tabla.find($id.getText());
            if (entrada == null)
               System.out.println("Error semantico, no encontrada variable " + $id.getText());
            else {
               $etipo = entrada.getETipo();
               $ref = false;
               $offset = entrada.getOffset();
               $blockLevel = entrada.getBlockLevel();
               genCall("SB", $id.getText()); 
               genComment("llamada de funcion " + $id.getText());
            } 
        };  
          
        
argument_list: binary 
            /*{ EntryTS entrada = tabla.find(
            genCall();
            } */
            (COMMA b2=binary)*; 


variable returns [ETipo etipo, boolean ref, int offset, int blockLevel]: 
       id=ID 
       {  EntryTS entrada = tabla.find($id.getText());
          if (entrada == null)
            System.out.println("Error semantico, no encontrada variable" + $id.getText());
          else {
             $etipo = entrada.getETipo(); 
             
             $ref = false;
             $offset = entrada.getOffset();
             $blockLevel = entrada.getBlockLevel();
             
             if (tabla.isGlobal($id.getText()))
                gen("LOAD", $etipo.getSize(), entrada.getOffset(), "SB");
             else
                gen("LOAD", $etipo.getSize(), entrada.getOffset(), "LB");
             
             genComment($id.getText());
          }
       }
       
       | ASTERISK id=ID
       {  EntryTS entrada = tabla.find($id.getText());
          if (entrada == null)
             System.out.println("Error semantico, no encontrada variable" + $id.getText());
          else {
             if (entrada.getTipo() == Tipos.POINTER) {
               if (entrada.getApuntado() == null) {
                  $etipo = new ETipo_Int(); //por defecto
                  System.out.println("Error semantico: la variable " + $id.getText() + "apunta a null");
               }
               else
                  $etipo = entrada.getApuntado();
             }
             
             else {
               $etipo = new ETipo_Int(); //por defecto
               System.out.println("Error semantico: la variable " + $id.getText() + " no es un puntero");
             } 
               
             $ref = false;
             $offset = entrada.getOffset();
             $blockLevel = entrada.getBlockLevel();
             
             if (entrada.isGlobal())
                gen("LOADA", 1, entrada.getOffset(), "SB");
             else
                gen("LOADA", 1, entrada.getOffset(), "LB");
                
             //gen("STORE", entrada.getSize(), entrada.getETipo().
             genComment("*" + $id.getText());
          } //if entrada null
       }
       
       | AND_BIN ID
       {  EntryTS entrada = tabla.find($id.getText());
          if (entrada == null)
            System.out.println("Error semantico, no encontrada variable " + $id.getText());
          else {
             $etipo = entrada.getETipo(); 
             $ref = true;
             $offset = entrada.getOffset();
             $blockLevel = entrada.getBlockLevel();
             
             if (tabla.isGlobal($id.getText()))
                gen("LOADA", NULO, entrada.getOffset(), "SB");
             else
                gen("LOADA", NULO, entrada.getOffset(), "LB");
                
             genComment("&" + $id.getText());
           } //if entrada null
       };
       

assign_new returns [ETipo etipo, boolean ref, int offset, int blockLevel]:
        id=ID ASSIGN NEW t=type LPARENTHESIS e=expression RPARENTHESIS
        {
            $etipo = new ETipo_Pointer(); //de tamaño 1, con valor de expresion
            $etipo.setNewPuntero($t.etipo.getIdTipo(), $e.etipo.getValue(), $e.etipo.getDecimalValue()); 
            
            EntryTS entrada = tabla.find($id.getText());
            if (entrada == null)
                System.out.println("Error semantico, no encontrada variable " + $id.getText());
            else {
            	
	            if (entrada.getTipo() != Tipos.POINTER)
	               System.out.println("Error: variable " + $id.getText() + " no es de tipo puntero");
	              
	            entrada.setETipo($etipo); //comprobar que se modificaaaaa en la TABLA: SIIII
	            
	            $ref = false;
	            $offset = entrada.getOffset();
	            $blockLevel = entrada.getBlockLevel();
	            /*$etipo = $t.etipo;
	            $etipo.setValue($e.etipo.getValue()); //no problem: si no tiene el campo la funcion sera vacia
	            $etipo.setDecimalValue($e.etipo.getDecimalValue());
	            $etipo.setPuntero($e.etipo.getPuntero()); //no haria falta en general*/
	            genCall(new Long($t.etipo.getSize()).intValue(), "new"); //tam tipo * 1
                genComment($id.getText() + " = " + Tipos.getTipoStr($t.etipo.getIdTipo()) + " new(" + $e.etipo.getValue() + ")");
            } //else
        }
        
        | id=ID ASSIGN NEW t=type LBRACKET e=expression RBRACKET
        {
            $etipo = new ETipo_Pointer(); //tamaño N (expression), todo vacio
            $etipo.setNewPuntero($t.etipo.getIdTipo(), new Long($e.etipo.getValue()).intValue()); //de tamaño N
            
            EntryTS entrada = tabla.find($id.getText());
            if (entrada == null)
                System.out.println("Error semantico, no encontrada variable " + $id.getText());
            else {
                
                if (entrada.getTipo() != Tipos.POINTER)
                   System.out.println("Error: variable " + $id.getText() + " no es de tipo puntero");
                   
	            entrada.setETipo($etipo); //comprobar que se modificaaaaa en la TABLA: SIIII
	            
	            $ref = false;
	            $offset = entrada.getOffset();
	            $blockLevel = entrada.getBlockLevel();
	            
	            genCall(new Long($t.etipo.getSize() * $e.etipo.getValue()).intValue(), "new");
	            genComment($id.getText() + " = " + Tipos.getTipoStr($t.etipo.getIdTipo()) + " new[" + $e.etipo.getValue() + "]");
            } //else
        };
        
